
#import "MyView.h"
#import <OpenGLES/EAGLDrawable.h>
#import <QuartzCore/QuartzCore.h>
#include "gameApp.h"
#include "vec2.h"
#import "Texture2D.h"

#define kAccelerometerFrequency		10 //Hz
#define kFilteringFactor			0.1

@implementation MyViewController
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error 
{	
	[self dismissModalViewControllerAnimated:YES];
}
@end

@interface MyView (MyViewPrivate)

- (void)initGame;
- (void)createOpenGL;
- (BOOL)createFramebuffer;
- (void)destroyFramebuffer;
- (void)buildSoundEngine;
@end

@implementation MyView

@synthesize m_ViewController;

// You must implement this
+ (Class) layerClass
{
	return [CAEAGLLayer class];
}

-(void)SetInterrupt:(bool)interrupt
{
	m_interrupt = interrupt;
	CGameApp::SetGameInterrupt(m_interrupt);
}

-(void)buildSoundEngine
{
#ifndef NO_SOUND
	// [20090310 aNdy] continue play user's music when playing game
	 
	// initialize the audio session object for this application,
	// registering the callback that Audio Session Services will invoke 
	// when there's an interruption
	// NOTE: this should be done only once	
	AudioSessionInitialize
	(
		NULL,
		NULL,
		CGameApp::GameAppInterruptionListener,
		NULL 
	);
	
	// set the audio session category
	// received the following feedback from Apple:
	// In Timberline we have changed the default category for playback from 
	// "kAudioSessionCategory_MediaPlayback," to "kAudioSessionCategory_SoloAmbientSound" 
	// (see <rdar://problem/6213349).  With this change, games which use the default
	// category will obey the ringer switch.  We tested top 100 games in house and 
	// found that some of them don't obey the ringer switch either because did set a category
	// or because they are using "kAudioSessionCategory_MediaPlayback.  
	// We would like the developers to use "kAudioSessionCategory_SoloAmbientSound" for their 
	// games.
	UInt32 sessionCategory = kAudioSessionCategory_AmbientSound;
	AudioSessionSetProperty 
	(
		kAudioSessionProperty_AudioCategory,
		sizeof (sessionCategory),
		&sessionCategory
	);
#endif //#ifndef NO_SOUND
}

- (id) initWithFrame:(CGRect)frame
{
	// run default init...
	self = [super initWithFrame:frame];
	
	// Set up the ability to track multiple touches.
	[self setMultipleTouchEnabled:NO];
	
	// run our setup routines
	[self createOpenGL];
	[self buildSoundEngine];
	[self initGame];

	m_ViewController = [[MyViewController alloc] init];
	m_ViewController.view = self;
	
	return self;
}
enum{CON_STATE_NON,CON_STATE_INPUT,CON_STATE_REMOVE};
static int16 conState = CON_STATE_NON;
- (void)AddControll
{
	CGameControll* pconData  = CGameApp::GetControllData();

	if(pconData->conType == GCON_EDITOR)
	{
		CGRect contRect = CGRectMake(pconData->conArea.x, 
									 pconData->conArea.y, 
									 pconData->conArea.dx, 
									 pconData->conArea.dy);
		if (pconData->isMultiLine) 
		{
			UITextView * inputEditor = [[UITextView alloc] initWithFrame:contRect];
			inputEditor.textColor = [UIColor blackColor];
			inputEditor.font = [UIFont fontWithName:(NSString*)pconData->fontName.GetNSString() size:pconData->fontSize];
			inputEditor.backgroundColor = [UIColor whiteColor];
			inputEditor.autocorrectionType = UITextAutocorrectionTypeNo;
			inputEditor.autocapitalizationType = UITextAutocapitalizationTypeNone;
			
			inputEditor.keyboardType = (UIKeyboardType)pconData->keyBoardType;
			inputEditor.returnKeyType = (UIReturnKeyType)pconData->returnKeyType;
			inputEditor.enablesReturnKeyAutomatically = YES;
			inputEditor.secureTextEntry = pconData->isPassWord;
			//inputEditor.editable = false;
			
			inputEditor.tag = 0; // tag this control so we can remove it later for recycled cells
			inputEditor.delegate = self;
			
			if(pconData->resultTxt.GetLength() > pconData->maxInputNum)
				pconData->resultTxt = pconData->resultTxt.SubString(0, pconData->maxInputNum);
			
			if(pconData->resultTxt.GetLength() > 0)
				inputEditor.text = (NSString*)pconData->resultTxt.GetNSString();
			
			[[self superview] addSubview:inputEditor];
			[inputEditor becomeFirstResponder];
			
			m_GControll = inputEditor;
		}
		else 
		{
			UITextField * inputEditor = [[UITextField alloc] initWithFrame:contRect];
			inputEditor.enabled = TRUE;
			inputEditor.borderStyle = UITextBorderStyleNone;
			inputEditor.textColor = [UIColor blackColor];
			inputEditor.font = [UIFont fontWithName:(NSString*)pconData->fontName.GetNSString() size:pconData->fontSize];
			inputEditor.placeholder = (NSString*)pconData->nullTxt.GetNSString();
			inputEditor.backgroundColor = [UIColor whiteColor];
			inputEditor.autocorrectionType = UITextAutocorrectionTypeNo;
			inputEditor.autocapitalizationType = UITextAutocapitalizationTypeNone;
			
			inputEditor.keyboardType = (UIKeyboardType)pconData->keyBoardType;
			inputEditor.returnKeyType = (UIReturnKeyType)pconData->returnKeyType;
			inputEditor.enablesReturnKeyAutomatically = YES;
			inputEditor.secureTextEntry = pconData->isPassWord;
			
			if(pconData->isNeedClearBtn)
				inputEditor.clearButtonMode = UITextFieldViewModeWhileEditing;
			
			inputEditor.tag = 0; // tag this control so we can remove it later for recycled cells
			inputEditor.delegate = self;
			
			if(pconData->resultTxt.GetLength() > pconData->maxInputNum)
				pconData->resultTxt = pconData->resultTxt.SubString(0, pconData->maxInputNum);
			
			if(pconData->resultTxt.GetLength() > 0)
				inputEditor.text = (NSString*)pconData->resultTxt.GetNSString();
			
			[[self superview] addSubview:inputEditor];
			[inputEditor becomeFirstResponder];
			[inputEditor addTarget:self action:@selector(textFieldDone:) forControlEvents:UIControlEventEditingDidEndOnExit];
			[inputEditor addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
			m_GControll = inputEditor;
		}
		conState = CON_STATE_INPUT;
	}
	else if(pconData->conType == GCON_SELECT)
	{
		CGRect contRect = CGRectMake(0, 
									 pconData->conArea.y, 
									 0, 
									 0);
		UIPickerView * pickerview = [[UIPickerView alloc] initWithFrame:contRect];
		pickerview.delegate = self;
		pickerview.showsSelectionIndicator = YES;
		
		[[self superview] addSubview:pickerview];
		for(int i=0;i<pconData->dataSelectNum;i++)
		{
			[pickerview selectRow:pconData->dataSelect[i] inComponent:i animated:NO];
		}
		m_GControll = pickerview;
		conState = CON_STATE_INPUT;
	}
	else if(pconData->conType == GCON_NOTE)
	{
		UIAlertView* alertView = [[UIAlertView alloc]
								  initWithTitle:(NSString *)pconData->title.GetNSString()
								  message:(NSString *)pconData->message.GetNSString()
								  delegate:self 
								  cancelButtonTitle:nil 
								  otherButtonTitles:nil];
		if(pconData->lBtnName.GetLength() > 0)
			[alertView addButtonWithTitle:(NSString *)pconData->lBtnName.GetNSString()];
		if(pconData->rBtnName.GetLength() > 0)
			[alertView addButtonWithTitle:(NSString *)pconData->rBtnName.GetNSString()];
		[alertView show];
		[alertView release];
	}
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
	CGameControll* pconData  = CGameApp::GetControllData();
	if(buttonIndex == 0)
		pconData->btnSelectId = pconData->lBtnId;
	else if(buttonIndex == 1)
		pconData->btnSelectId = pconData->rBtnId;
	pconData->callBackEvent = GCON_EVENT_BTN;
	CGameApp::ControllCallBack();
	CGameApp::DeleteControll();
}
			
- (void)DelControll
{
	if(conState != CON_STATE_NON)
	{
		conState = CON_STATE_NON;
		[m_GControll removeFromSuperview];
	}
}

- (void)textFieldDone:(id)sender
{
	CGameControll* pconData  = CGameApp::GetControllData();
	pconData->resultTxt.Copy([((UITextField*)m_GControll).text UTF8String]);
	pconData->callBackEvent = GCON_EVENT_BTN;
	CGameApp::ControllCallBack();
	conState = CON_STATE_REMOVE;
}

-(void) textFieldDidChange:(UITextField*) textField 
{
	CGameControll* pconData  = CGameApp::GetControllData();
	if([((UITextField*)m_GControll).text length] > pconData->maxInputNum)
		((UITextField*)m_GControll).text = [((UITextField*)m_GControll).text substringToIndex:pconData->maxInputNum];
}

- (void)textViewDidChange:(UITextView *)textView
{
	CGameControll* pconData  = CGameApp::GetControllData();
	if([((UITextView*)m_GControll).text length] > pconData->maxInputNum)
		((UITextView*)m_GControll).text = [((UITextView*)m_GControll).text substringToIndex:pconData->maxInputNum];
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
	CGameControll* pconData  = CGameApp::GetControllData();
    if (range.location >= pconData->maxInputNum &&
		[string length] > 0 &&
		![string isEqualToString:@"\n"])return NO;
    return YES;
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
	CGameControll* pconData  = CGameApp::GetControllData();
	if (range.location >= pconData->maxInputNum &&
		[text length] > 0)return NO;
    return YES;
}

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView*)pickerView
{
	CGameControll* pconData  = CGameApp::GetControllData();
	return pconData->dataSelectNum;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
	CGameControll* pconData  = CGameApp::GetControllData();
	return pconData->dataList[component].Count();
}

- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component
{
	CGameControll* pconData  = CGameApp::GetControllData();
	return pconData->conArea.dx;
}

/*
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
	CGameControll* pconData  = CGameApp::GetControllData();
	return pconData->conArea.dy;
}
*/
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
	CGameControll* pconData  = CGameApp::GetControllData();
	return (NSString*)pconData->dataList[component].GetData(row)->GetNSString();
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
	//NSString *result = [pickerView pickerView:pickerView titleForRow:row forComponent:component];
	CGameControll* pconData  = CGameApp::GetControllData();
	for(int i=0;i<pconData->dataSelectNum;i++)
	{
		pconData->dataSelect[i] = [(UIPickerView*)m_GControll selectedRowInComponent:i];
	}
	
	pconData->callBackEvent = GCON_EVENT_BTN;
	CGameApp::ControllCallBack();

	pconData  = CGameApp::GetControllData();
	if(pconData)
	{
		[(UIPickerView*)m_GControll reloadAllComponents];
		for(int i=0;i<pconData->dataSelectNum;i++)
		{
			[(UIPickerView*)m_GControll selectRow:pconData->dataSelect[i] inComponent:i animated:NO];
		}
	}
}

- (void)OnTimer
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	if (m_interrupt)
	{ // stop the game tick when interrupt
		return;
	}

	if(conState != CON_STATE_NON)
	{
		CGameControll* pconData  = CGameApp::GetControllData();
		
		if(conState == CON_STATE_INPUT)
		{
			_Rect r(0,0,CGameApp::ScreenWidth(),CGameApp::ScreenHeight());
			if(CGameApp::GetTouchInput()->HitsRect(&r))
			{
				if(pconData->conType != GCON_NOTE)
				{
					conState = CON_STATE_REMOVE;
					if(pconData->conType == GCON_EDITOR && pconData->isAutoCopyResult)
					{
						if (pconData->isMultiLine)
							pconData->resultTxt.Copy([((UITextView*)m_GControll).text UTF8String]);
						else
							pconData->resultTxt.Copy([((UITextField*)m_GControll).text UTF8String]);
					}
					if(pconData->isRemoveCallBack)
					{
						pconData->callBackEvent = GCON_EVENT_REMOVE;
						CGameApp::ControllCallBack();
					}
				}
			}
		}
		if(pconData->isLockTouch)CGameApp::GetTouchInput()->Clear();
	}
	
	int timeNow = GETTIMEMS();
	// update and draw the game
	CGameApp::HandleUpdate(timeNow  - m_iLastTime);
	CGameApp::HandleRender();
	
	// reset touch input
	CGameApp::GetTouchInput()->Reset();
	
	// push to the screen
	EAGLContext *oldContext = [EAGLContext currentContext];
	
	if( oldContext != context )
		[EAGLContext setCurrentContext:context];
	
	[context presentRenderbuffer:GL_RENDERBUFFER_OES];
	
	if(oldContext != context)
		[EAGLContext setCurrentContext:oldContext];
	
	m_iLastTime = timeNow;
	
	if(conState == CON_STATE_REMOVE)
	{
		CGameApp::DeleteControll();
	}
}

- (void) layoutSubviews
{
	[self destroyFramebuffer];
	[self createFramebuffer];
}

static int numTouches = 0;

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
	numTouches += [touches count];
	
	for (UITouch * touch in touches)
	{
		CGPoint location = [touch locationInView:self];
		
		vec2 hit;
		hit.x = (int32)( location.x * ( 1024 ) );
		hit.y = (int32)( location.y * ( 1024 ) );
		
		CGameApp::GetTouchInput()->HandleEvent( TOEV_DOWN, &hit, [touch timestamp] * 1000, [touch tapCount], numTouches );
	}
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{	
	for (UITouch * touch in touches)
	{
		CGPoint location = [touch locationInView:self];
		
		vec2 hit;
		hit.x = (int32)( location.x * ( 1024 ) );
		hit.y = (int32)( location.y * ( 1024 ) );
		
		CGameApp::GetTouchInput()->HandleEvent( TOEV_MOVE, &hit, [touch timestamp] * 1000, [touch tapCount], numTouches );
	}
}

- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{	
	numTouches -= [touches count];
	
	for (UITouch * touch in touches)
	{
		CGPoint location = [touch locationInView:self];
		
		vec2 hit;
		hit.x = (int32)( location.x * ( 1024 ) );
		hit.y = (int32)( location.y * ( 1024 ) );
		
		
		CGameApp::GetTouchInput()->HandleEvent( TOEV_UP, &hit, [touch timestamp] * 1000, [touch tapCount], numTouches );
	}
}

- (void) touchesCanceled
{	
	numTouches = 0;
	vec2 hit;
	hit.x = hit.y = -1;
	CGameApp::GetTouchInput()->HandleEvent( TOEV_CANCEL, &hit, 0, 0, 0 );
}

- (void) accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
{
	// SPA - increase accelerometer sensitivity by a factor of 10
	CGameApp::GetTouchInput()->HandleAccelerometer( acceleration.x, acceleration.y, acceleration.z );
	// CGameApp::GetTouchInput()->HandleAccelerometer( acceleration.x * 10, acceleration.y * 10, acceleration.z * 10 );
}

- (void)onExit
{
    CGameApp::OnFree();
	[m_ViewController release];
}

- (void)initGame
{
	m_iLastTime = GETTIMEMS();
	// intialize core components
	CGameApp::OnInit(self);
	
	//Configure and start accelerometer
	[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / kAccelerometerFrequency)];
	[[UIAccelerometer sharedAccelerometer] setDelegate:self];
	
	// Start game timer
	m_Timer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / 30.0) target:self selector:@selector(OnTimer) userInfo:nil repeats:YES];
}

- (void)createOpenGL
{	
	// get the rect for our screen
	CGRect rect = [[UIScreen mainScreen] bounds];
	
	// get our view layer
	CAEAGLLayer *eaglLayer = (CAEAGLLayer*)self.layer;
	
	// make opaque for efficiency
	eaglLayer.opaque = YES;
	
	eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
									[NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
	
	
	// create the OpenGL context
	context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];	
	// apply our context
	[EAGLContext setCurrentContext:context];
	
	// create the render surface we'll be using
	[self createFramebuffer];
	
	glClearColor(0, 0, 0, 1);
	
	glViewport(0, 0, rect.size.width, rect.size.height);
	glScissor(0, 0, rect.size.width, rect.size.height);
	glEnable(GL_SCISSOR_TEST);
	
	// setup OpenGL projection matrix
	glMatrixMode(GL_PROJECTION);
	glOrthof(0, rect.size.width, rect.size.height, 0, -100, 100);
	glMatrixMode(GL_MODELVIEW);
	
	// setup default OpenGL states
	// http://www.idevapps.com/forum/archive/index.php/t-5351.html
	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
	//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_TEXTURE_2D);
	glDisable(GL_DEPTH_TEST);
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glEnable(GL_BLEND);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

- (BOOL)createFramebuffer
{
	// create a frame buffer & a render buffer
	glGenFramebuffersOES(1, &viewFramebuffer);
	glGenRenderbuffersOES(1, &viewRenderbuffer);
	
	// bind our frame & render buffers
	glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
	glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
	
	// attach our window layer to this render buffer
	[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer];
	glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
	
	// get the width & height of our render buffer
	glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
	glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
	
	if (USE_DEPTH_BUFFER) 
	{
		glGenRenderbuffersOES(1, &depthRenderbuffer);
		glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
		glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
		glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
	}
	
	// verify everything went OK
	if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
		NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
		return NO;
	}
	
	glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
	return YES;
}

- (void)destroyFramebuffer
{
	glDeleteFramebuffersOES(1, &viewFramebuffer);
	viewFramebuffer = 0;
	
	glDeleteRenderbuffersOES(1, &viewRenderbuffer);
	viewRenderbuffer = 0;
}

@end
